﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ZhCun.Utils
{
    /// <summary>
    /// 实现 Windows API
    /// </summary>
    public static class WinAPI
    {
        /// <summary>
        /// 查找窗口获取句柄
        /// </summary>
        /// <param name="lpClassName">类名</param>
        /// <param name="lpWindowName">窗体名</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        /// <summary>
        /// 查找指定窗口的的子窗口句柄
        /// </summary>
        /// <param name="hwndParent">要查找的子窗口所在的父窗口的句柄</param>
        /// <param name="hwndChildAfter">子窗口句柄。查找从在Z序中的下一个子窗口开始</param>
        /// <param name="lpszClass">类名</param>
        /// <param name="lpszWindows">窗口名（窗口标题）</param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindows);

        /// <summary>
        /// 窗口中指定参数ID的子元素的句柄，可以通过返回的句柄对窗口内的子元素进行操作
        /// </summary>
        /// <param name="hWnd">标识含有控件的对话框(所在窗口句柄)</param>
        /// <param name="nIDDlgItem">标识含有控件的对话框(控件ID)</param>
        /// <returns>返回控件句柄</returns>
        [DllImport("User32.dll")]
        public static extern IntPtr GetDlgItem(IntPtr hWnd, int nIDDlgItem);

        /// <summary>
        /// 枚举回调维护
        /// </summary>
        public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);

        /// <summary>
        /// 通过将句柄传递给每个子窗口并依次传递给应用程序定义的回调函数
        /// 直到枚举最后一个子窗口或回调函数返回FALSE为止
        /// </summary>
        /// <param name="hwndParent">父窗口的句柄，其子窗口将被枚举。如果此参数为NULL，则此函数等效于EnumWindows。</param>
        /// <param name="lpEnumFunc">指向应用程序定义的回调函数的指针</param>
        /// <param name="lParam">应用程序定义的值，将传递给回调函数</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, int lParam);
        /// <summary>
        /// 获取当前桌面窗口句柄
        /// </summary>
        [DllImport("User32.dll")]
        public static extern IntPtr GetDesktopWindow();
        /// <summary>
        /// 获取当前激活窗口的句柄
        /// </summary>
        [DllImport("User32.dll")]
        public static extern IntPtr GetActiveWindow();
        /// <summary>
        /// 获取当前激活窗口
        /// 获取一个前台窗口的句柄（用户当前工作的窗口）
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        public static extern IntPtr GetFocus();
        /// <summary>
        /// 设置此窗体为活动窗体
        /// </summary>
        [DllImport("user32.dll")]
        public static extern IntPtr SetFocus(IntPtr hWnd);


        /// <summary>
        /// 获得指定窗口所属的类的类名
        /// </summary>
        /// <param name="hWnd">窗口的句柄及间接给出的窗口所属的类</param>
        /// <param name="lpString">接收窗口类名字符串</param>
        /// <param name="nMaxCount">指定由参数lpClassName指示的缓冲区的字节数。如果类名字符串大于缓冲区的长度，则多出的部分被截断</param>
        /// <returns>如果函数成功，返回值为拷贝到指定缓冲区的字符个数：如果函数失败，返回值为0。若想获得更多错误信息，请调用GetLastError函数。</returns>
        [DllImport("user32.dll")]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        #region SendMessage => msg:  const

        //参考：https://baike.baidu.com/item/SendMessage

        /// <summary>
        /// 应用程序发送此消息来设置一个窗口的文本
        /// </summary>
        public const int WM_SETTEXT = 0x000C;
        /// <summary>
        /// 应用程序发送此消息来复制对应窗口的文本到缓冲区
        /// </summary>
        public const int WM_GETTEXT = 0x000D;
        /// <summary>
        /// 按下一个键
        /// </summary>
        public const int WM_KEYDOWN = 0x0100;
        /// <summary>
        /// 释放一个键
        /// </summary>
        public const int WM_KEYUP = 0x0101;
        /// <summary>
        /// 按下某键，并已发出WM_KEYDOWN， WM_KEYUP消息
        /// </summary>
        public const int WM_CHAR = 0x0102;

        /// <summary>
        /// 获取下拉列表数量
        /// </summary>
        public const int CB_GETCOUNT = 0x0146;
        /// <summary>
        /// 获取下拉列表文本
        /// </summary>
        public const int CB_GETLBTEXT = 0x0148;
        /// <summary>
        /// 设置下拉列表index, wParam : 为index 
        /// </summary>
        public const int CB_SETCURSEL = 0x014E;

        #endregion

        /// <summary>
        /// 该函数将指定的消息发送到一个或多个窗口。
        /// 此函数为指定的窗口调用窗口程序，直到窗口程序处理完消息再返回。
        /// 而和函数PostMessage不同，PostMessage是将一个消息寄送到一个线程的消息队列后就立即返回
        /// </summary>
        /// <param name="hWnd">指定要接收消息的窗口的句柄</param>
        /// <param name="Msg">指定被发送的消息</param>
        /// <param name="wParam">指定附加的消息特定信息</param>
        /// <param name="lParam">指定附加的消息特定信息</param>
        /// <returns>返回值指定消息处理的结果，依赖于所发送的消息</returns>
        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);

        /// <summary>
        /// 将一个线程的输入处理机制附加或分离到另一个线程的输入处理机制
        /// </summary>
        /// <param name="idAttach">指定要连接到另外一个线程的线程。该线程不能是系统线程</param>
        /// <param name="idAttachTo">要连接其他线程的线程，该线程不能是系统线程。且线程不能自己连接到自己。</param>
        /// <param name="fAttach">TRUE：连接； 为FALSE: 释放连接</param>
        /// <param name="lParam"></param>
        /// <returns>如果调用成功则返回非零值</returns>
        [DllImport("User32.dll")]
        public static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);

        /// <summary>
        /// 找出某个窗口的创建者（线程或进程），返回创建者的标志符（线程Id）
        /// </summary>
        /// <param name="hWnd">被查找窗口的句柄</param>
        /// <param name="lpdwProcessId">输出 进程号的存放地址（变量地址）</param>
        /// <returns>返回线程号，
        /// 注意，lpdwProcessId 是存放进程号的变量。返回值是线程号，lpdwProcessId 是进程号存放处。
        /// </returns>
        [DllImport("User32.dll")]
        public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
        ///// <summary>
        ///// 获取当前线程一个唯一的线程标识符
        ///// </summary>
        ///// <returns>返回当前的线程标识符</returns>
        //[DllImport("User32.dll")]
        //public static extern int GetCurrentThreadId();


    }
}
